package com.xhapi.service.impl;

import cn.hutool.json.JSONUtil;
import com.xhapi.mapper.HistoryQuestionByAiMapper;
import com.xhapi.pojo.entity.HistoryQuestionByAi;
import com.xhapi.pojo.entity.HistoryQuestionByAiDoc;
import com.xhapi.pojo.pageQuery.ElasticSearchPage;
import com.xhapi.service.ESService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpHost;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
@RequiredArgsConstructor
public class ESServiceImpl implements ESService {
    private RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(new HttpHost("192.168.88.95", 9200, "http")));
    private final HistoryQuestionByAiMapper mapper;

    /*
     * 先删除所有es内数据，再把MySQL数据导入
     * */
    @Override
    public void updateES() {
        deleteES();
        List<HistoryQuestionByAi> lists = mapper.selectList(null);
        BulkRequest request = new BulkRequest();
        lists.forEach(item -> {
            HistoryQuestionByAiDoc historyQuestionByAiDoc = new HistoryQuestionByAiDoc();
            BeanUtils.copyProperties(item, historyQuestionByAiDoc);
            historyQuestionByAiDoc.setQuestion_analysis(item.getAnalysis());
            request.add(new IndexRequest("question")
                    .id(item.getId().toString())
                    .source(JSONUtil.toJsonStr(historyQuestionByAiDoc), XContentType.JSON));
        });
        try {
            client.bulk(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    @Override
    public void addES(List<HistoryQuestionByAi> lists)  {
        BulkRequest request=new BulkRequest();
        lists.forEach(item->{
            HistoryQuestionByAiDoc doc=new HistoryQuestionByAiDoc();
            BeanUtils.copyProperties(item,doc);
            doc.setQuestion_analysis(item.getAnalysis());
            request.add(new IndexRequest("question")
                    .id(item.getId().toString())
                    .source(JSONUtil.toJsonStr(doc),XContentType.JSON)
            );
        });
        try{
            client.bulk(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new RuntimeException("数据写入失败！");
        }
    }
    /*
     * 删除ES内所有数据
     * */
    public void deleteES() {
        DeleteByQueryRequest request = new DeleteByQueryRequest("question").setQuery(QueryBuilders.matchAllQuery());
        try {
            client.deleteByQuery(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public ElasticSearchPage pageByES(int pageSize, int pageNum, String subject, String desc) {
        SearchRequest request = new SearchRequest("question");
        // 复合查询语句
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        // 通过desc加权模糊查询question，answer，analysis三个字段，如果subject不为空则全匹配字段
        if(subject!=null){
            boolQueryBuilder.filter(QueryBuilders.termQuery("subject",subject));
        }
        if(desc!=null){
            boolQueryBuilder.should(QueryBuilders.matchQuery("question",desc));
            boolQueryBuilder.should(QueryBuilders.matchQuery("question_analysis",desc));
            boolQueryBuilder.should(QueryBuilders.matchQuery("answer",desc));
        }else {
            boolQueryBuilder.must(QueryBuilders.matchAllQuery());
            // 在desc为空的时候才会进行按时间排序
            request.source().sort("update_time", SortOrder.DESC);
        }
        // 分页查询
        request.source().query(boolQueryBuilder).from((pageNum - 1) * pageSize).size(pageSize);

        //高亮显示
        HighlightBuilder highlightBuilder=new HighlightBuilder();
        highlightBuilder.field("question").preTags("<em style=\"color: red;\">").postTags("</em>");
        request.source().highlighter(highlightBuilder);
        // 获取结果信息
        try {
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);
            SearchHits hit = response.getHits();
            SearchHit[] hits = hit.getHits();
            List<HistoryQuestionByAi> list = new ArrayList<>();
            for (SearchHit documentFields : hits) {
                String source = documentFields.getSourceAsString();
                HistoryQuestionByAiDoc bean = JSONUtil.toBean(source, HistoryQuestionByAiDoc.class);
                HistoryQuestionByAi historyQuestionByAi=new HistoryQuestionByAi();
                BeanUtils.copyProperties(bean,historyQuestionByAi);
                historyQuestionByAi.setAnalysis(bean.getQuestion_analysis());
                // 将字段修改为高亮字段
                Map<String, HighlightField>highlightFields=documentFields.getHighlightFields();
                if(highlightFields!=null&& !highlightFields.isEmpty()){
                    HighlightField field = highlightFields.get("question");
                    historyQuestionByAi.setQuestion(field.fragments()[0].toString());
                }
                list.add(historyQuestionByAi);
            }
            long total = hit.getTotalHits().value;
            return ElasticSearchPage.builder()
                    .pages(total / list.size() + 1)
                    .list(list)
                    .total(total)
                    .build();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

}
